#pragma once
/*
    实现一些项目中用到的琐碎功能代码
    -日志宏的定义
    -json的序列化和反序列化
    -uuid的生成
*/
#include <stdio.h>
#include <time.h>
#include <jsoncpp/json/json.h>
#include <iostream>
#include <memory>

// 生成随机数的头文件
#include <chrono>
#include <random>
#include <string>
#include <sstream>
#include <iomanip>
#include <atomic>
// end 随机数头文件
using std::cout;
using std::endl;

namespace tmh_rpc
{
// 1. 日志宏的实现
// 加入日志等级
#define LDBG 0
#define LINF 1
#define LERR 2

#define LDEFAULT LDBG // 对代码进行调试
// #define LDEFAULT LINF // 默认日志是不打印的

#define LOG(level, format, ...)                                                              \
    {                                                                                        \
        if (level >= LDEFAULT)                                                               \
        {                                                                                    \
            time_t t = time(nullptr);                                                        \
            struct tm *lt = localtime(&t);                                                   \
            char time_tmp[32] = {0};                                                         \
            strftime(time_tmp, 31, "%m-%d %T", lt);                                          \
            printf("[%s][%s:%d] " format "\n", time_tmp, __FILE__, __LINE__, ##__VA_ARGS__); \
        }                                                                                    \
    }

// 再次对日志宏进行宏定义
#define DLOG(format, ...) LOG(LDBG, format, ##__VA_ARGS__);
#define ILOG(format, ...) LOG(LINF, format, ##__VA_ARGS__);
#define ELOG(format, ...) LOG(LERR, format, ##__VA_ARGS__);

    // end 日志宏的实现

    class JSON
    {
    public:
        // 2. json序列化和反序列化
        //  序列化
        static bool serialize(const Json::Value &stu, std::string &body)
        {
            std::stringstream ss;
            // 3. StreamWiterBuilder对象用于生产StreamWriter
            Json::StreamWriterBuilder swb; // 工厂类用于生产streamwriter

            // 4. 生产StreamWriter对象
            std::unique_ptr<Json::StreamWriter> sw(swb.newStreamWriter()); // 父类指针指向子类对象初始化

            // 5. 序列化
            int ret = sw->write(stu, &ss);
            if (ret != 0)
            {
                // std::cout << "json serialize failed!" << std::endl;
                ELOG("json serialize failed!");
                return false;
            }
            body = ss.str();
            return true;
            // 6. 释放堆对象，防止内存泄漏
            //  delete sw;
        }
        // 反序列化
        static bool deserialize(const std::string &body, Json::Value &val)
        {
            // 1. CharReaderBuilder对象用于生产CharReader对象
            Json::CharReaderBuilder crb;

            // 2. 生产CharReader对象
            std::unique_ptr<Json::CharReader> cr(crb.newCharReader()); // 父类指针指向子类对象

            // 3. 反序列化
            std::string errs;
            bool ret = cr->parse(body.c_str(), body.c_str() + body.size(), &val, &errs);
            if (ret == false)
            {
                // std::cout << "json deserialize failed: " << errs << std::endl;
                ELOG("json deserialize failed: %s", errs.c_str());
                return false;
            }
            return true;
        }

        // end json序列化、反序列化
    };

    class UUID
    {
    public:
        // 生成uuid的函数: 全局唯一
        static std::string uuid()
        {
            // 1. 构造一个机器[硬件]随机数对象
            std::random_device rd;
            // 2. 以机器随机数为种子构造伪随机数对象
            std::mt19937 generator(rd());
            // 3. 构造限定数据范围的对象
            std::uniform_int_distribution<int> distribution(0, 255);
            // 4. 生成8个随机数，按照特定格式组织成为16进制数字字符的字符串
            std::stringstream ss;
            // UUID的标准型式包含32个16进制数字字符，以连字号分为五段，形式为8-4-4-4-12的32个字符
            for (int i = 0; i < 8; i++)
            {
                if (i == 4 || i == 6)
                    ss << "-";
                // std::setw() 设置宽度，setfill() 不够的话前面补0，std::hex() 转16进制
                ss << std::setw(2) << std::setfill('0') << std::hex << distribution(generator);
            }
            ss << "-";
            // 5. 定义一个8字节序号，逐字节组织成为16进制数字字符的字符串
            static std::atomic<size_t> seq(1);
            ssize_t cur = seq.fetch_add(1);
            // 将8字节数据转换为16字节
            for (int i = 7; i >= 0; --i)
            {
                if (i == 5)
                    ss << "-";
                ss << std::setw(2) << std::setfill('0') << std::hex << ((cur >> (i * 8)) & 0xFF);
            }

            return ss.str();
        }
        // end uuid的设计
    };
}